Skip to content

Fix/deduplicate contributor fetching - #884

Open
Oluwasuyi-Oluwatimilehin-Daniel wants to merge 13 commits into
Iris-IV:mainfrom
Oluwasuyi-Oluwatimilehin-Daniel:fix/deduplicate-contributor-fetching
Open

Fix/deduplicate contributor fetching#884
Oluwasuyi-Oluwatimilehin-Daniel wants to merge 13 commits into
Iris-IV:mainfrom
Oluwasuyi-Oluwatimilehin-Daniel:fix/deduplicate-contributor-fetching

Conversation

@Oluwasuyi-Oluwatimilehin-Daniel

Copy link
Copy Markdown

#closes #831

PR: Deduplicate Wallet Transaction Fetching

Issue

#831 [Performance] useTopContributors and useContributorLeaderboard-style hooks duplicate fetching for the same campaign

Problem

useTopContributors and useContributions both independently fetch wallet transaction data using different React Query keys:

  • useTopContributors: key ["top-contributors", campaignId, userWalletAddress, limit]
  • useContributions: key ["contributions", walletAddress]

When both hooks are used on the same page (e.g., cause detail page with contributor leaderboard), the same wallet transaction data is fetched and processed twice, causing unnecessary network requests and processing overhead.

Solution

Created a shared useWalletTransactions hook with a consistent React Query key ["wallet-transactions", walletAddress] to enable request deduplication across all components that need wallet transaction data.

Changes Made

  1. Created src/hooks/useWalletTransactions.ts - New shared hook for fetching wallet transactions
  2. Updated src/hooks/useTopContributors.ts - Now uses shared useWalletTransactions hook
  3. Updated src/hooks/useContributions.ts - Now uses shared useWalletTransactions hook
  4. Updated src/components/TransactionHistorySection.tsx - Now uses shared useWalletTransactions hook
  5. Added src/hooks/__tests__/useWalletTransactions.test.tsx - Test confirming request deduplication

Acceptance Criteria

  • ✅ Confirmed that useTopContributors and useContributions overlap in data source (both call getWalletTransactions)
  • ✅ Shared single React Query key between them (["wallet-transactions", walletAddress])
  • ✅ Added test confirming request de-duplication

Testing

Added test in useWalletTransactions.test.tsx that verifies:

  • Wallet transactions are fetched with consistent React Query key
  • Requests are deduplicated when called with same wallet address
  • No fetch occurs when wallet address is null

Out of Scope

  • Changing the ranking algorithm itself (as specified in requirements)

Files Changed

  • src/hooks/useWalletTransactions.ts (new)
  • src/hooks/useTopContributors.ts
  • src/hooks/useContributions.ts
  • src/components/TransactionHistorySection.tsx
  • src/hooks/__tests__/useWalletTransactions.test.tsx (new)

Branch

fix/deduplicate-contributor-fetching
#closes

- Add docs/observability.md with architecture overview
- Document event types, categories, and data flow
- Provide step-by-step guide for adding new event types
- Link observability docs from main README
@sshdopey

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@Oluwasuyi-Oluwatimilehin-Daniel Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Comment thread src/hooks/__tests__/useWalletTransactions.test.tsx Fixed
@Oluwasuyi-Oluwatimilehin-Daniel
Oluwasuyi-Oluwatimilehin-Daniel force-pushed the fix/deduplicate-contributor-fetching branch from e98d4c6 to cca6d65 Compare July 30, 2026 10:22
@sshdopey

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

- Add 'Developing Without a Live Network' section to README.md
- Document NEXT_PUBLIC_USE_MOCKS flag and its purpose
- Explain DevMockPanel UI functionality
- List all available mock scenarios with descriptions
- Provide step-by-step guide for adding new mock scenarios

- Cross-reference issue Iris-IV#343 for production build protection
- Document relevant mock data files

Closes Iris-IV#839
- Create generic typed localStorage store helper (localStorageStore.ts)
- Refactor adminLog.ts to use shared helper
- Refactor transactionLog.ts to use shared helper
- Refactor notifications.ts to use shared helper
- Refactor preferences.ts to use shared helper
- Refactor contributorLeaderboard.ts to use shared helper
- Refactor analytics.ts to use shared helper
- Refactor eventSubscriber.ts to use shared helper

This consolidates duplicate localStorage read/write/JSON-parse boilerplate
across multiple modules into a single typed helper, making future backend
migration a single-point change instead of multiple changes.

Addresses Iris-IV#835
- Create useWalletTransactions hook with consistent React Query key
- Update useTopContributors to use shared wallet transactions hook
- Update useContributions to use shared wallet transactions hook
- Update TransactionHistorySection to use shared wallet transactions hook
- Add test confirming request deduplication

Fixes Iris-IV#831
@Oluwasuyi-Oluwatimilehin-Daniel
Oluwasuyi-Oluwatimilehin-Daniel force-pushed the fix/deduplicate-contributor-fetching branch from cca6d65 to 149fee3 Compare August 1, 2026 15:56
Copilot AI review requested due to automatic review settings August 1, 2026 15:56
@sshdopey

sshdopey commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a shared useWalletTransactions React Query hook intended to deduplicate wallet-transaction reads across contributor- and history-related UI, while also centralizing localStorage access via a typed helper and updating assorted UI/tests/docs.

Changes:

  • Added useWalletTransactions and migrated useTopContributors, useContributions, and TransactionHistorySection to use it.
  • Added a generic localStorageStore helper and refactored multiple libs to use it.
  • Updated a broad set of UI components, tests, i18n messages, scripts, and docs (including new observability docs).

Reviewed changes

Copilot reviewed 46 out of 46 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/e2e/withdrawal.spec.ts Formatting-only updates in the withdrawal E2E flow test.
src/lib/transactionLog.ts Switched wallet tx log storage to localStorageStore helpers.
src/lib/preferences.ts Refactored preference/theme/locale storage logic to reuse storage helpers.
src/lib/notifications.ts Refactored notification read-state storage to use localStorageStore.
src/lib/localStorageStore.ts New typed helper module for localStorage read/write patterns.
src/lib/gamification.ts Formatting/consistency updates (string quotes, trailing commas, layout).
src/lib/eventSubscriber.ts Persisted cursor read/write refactored to localStorageStore.
src/lib/contributorLeaderboard.ts Refactored anonymous preference storage to localStorageStore.
src/lib/analytics.ts Refactored analytics opt-in/out storage to localStorageStore.
src/lib/adminLog.ts Refactored admin audit log storage to localStorageStore.
src/hooks/useWalletTransactions.ts New shared React Query hook for wallet transaction retrieval.
src/hooks/useTopContributors.ts Now derives contributor aggregation from useWalletTransactions.
src/hooks/useReducedMotion.ts Added guards for SSR/older browser APIs for reduced-motion detection.
src/hooks/useDonationGracePeriod.ts Formatting/consistency updates.
src/hooks/useContributions.ts Now uses useWalletTransactions tx log when building contribution history.
src/hooks/tests/useWalletTransactions.test.tsx New unit tests for useWalletTransactions caching/dedup behavior.
src/context/DonationContext.tsx Formatting/consistency updates.
src/components/WalletContext.tsx Formatting (import wrapping, dependency array formatting).
src/components/TransactionHistorySection.tsx Migrated to useWalletTransactions instead of manual localStorage reads.
src/components/Skeleton.tsx Added data-testid="skeleton" to support tests.
src/components/NotificationSettings.tsx Formatting of memoized preference labels.
src/components/MyContributionsSection.tsx Added additional status label/class handling for new statuses.
src/components/LanguageSwitcher.tsx Adjusted live-region announcement behavior and related test expectations.
src/components/DonatorBadges.tsx Formatting/consistency updates.
src/components/ContributorLeaderboard.tsx Minor formatting adjustments.
src/components/CancelDonationBanner.tsx Formatting adjustment for remaining time calculation.
src/components/CampaignMap.tsx Minor formatting adjustments.
src/app/[locale]/causes/new/NewCauseClient.tsx Improved contract error toast handling with translations.
src/tests/pages/CreateCampaignPage.test.tsx Updated i18n mocking and revenue-share slider expectations.
src/tests/lib/contractClient.test.ts Updated server mock account structure.
src/tests/integration/CampaignUpdates.test.tsx Updated mocks and expectations (skeleton count, copy matching, signature verify).
src/tests/hooks/usePlatformFee.test.tsx Formatting of imports.
src/tests/components/UpdatesList.test.tsx Updated skeleton count and feed role assertions.
src/tests/components/UpdateComposer.test.tsx Updated copy/placeholder matching and character count assertions.
src/tests/components/MyContributionsSection.test.tsx Updated assertions to match new visible labels/buttons.
src/tests/components/LanguageSwitcher.test.tsx Updated interaction approach and live-region assertion.
src/tests/components/ContributorLeaderboard.test.tsx Updated next-intl mocks and loosened text matching.
src/tests/components/CommentItem.test.tsx Added ToastProvider mock to stabilize tests.
src/tests/app/sitemap.test.ts Updated campaign fixture fields.
scripts/find-unused-i18n-keys.js Formatting/consistency updates.
scripts/check-i18n.mjs Formatting/consistency updates.
README.md Added mock-mode guidance and new observability section (currently has encoding issues).
PRE_COMMIT_SETUP.md Removed stray blank lines.
messages/es.json Added Notifications translations.
messages/en.json Added Notifications translations.
docs/observability.md New documentation describing the observability module design and usage.
Suppressed comments (1)

README.md:299

  • This heading contains an invalid replacement character ("�") before the shield emoji, which indicates a text encoding issue and will render incorrectly.

Replace the heading with a valid string.

## �🛡 Error Reporting

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +129 to +133
const { transactions } = useWalletTransactions(walletAddress);

const { data, isLoading, isFetching, error } = useQuery<ContributionHistoryItem[], Error>({
queryKey: ["contributions", walletAddress],
queryFn: () => fetchContributionHistory(walletAddress!),
queryFn: () => fetchContributionHistory(walletAddress!, transactions),
Comment thread src/hooks/useWalletTransactions.ts Outdated
export function useWalletTransactions(walletAddress: string | null) {
const { data, isLoading, refetch } = useQuery<WalletTransactionLogEntry[]>({
queryKey: ["wallet-transactions", walletAddress],
queryFn: () => getWalletTransactions(walletAddress!),
Comment on lines +12 to +14
export function canUseStorage(): boolean {
return typeof window !== "undefined" && typeof window.localStorage !== "undefined";
}
Comment thread README.md Outdated
```

## 🛡 Error Reporting
## � Observability
Comment thread README.md Outdated
Comment on lines +295 to +297
## � Observability

The application includes an internal observability module for monitoring contract interactions, transaction flows, and RPC operations. See [docs/observability.md](docs/observability.md) for architecture details, event types, and instructions on adding new observability events.
Comment thread src/hooks/useTopContributors.ts Outdated
const { transactions } = useWalletTransactions(userWalletAddress);

const { data, isLoading, refetch } = useQuery<ContributorLeaderboardItem[]>({
queryKey: ["top-contributors", campaignId, userWalletAddress, limit],
Comment on lines +52 to +54
// getWalletTransactions should only be called once due to React Query caching
expect(getWalletTransactions).toHaveBeenCalledTimes(1);
await waitFor(() => {
@sshdopey

sshdopey commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@Oluwasuyi-Oluwatimilehin-Daniel
Oluwasuyi-Oluwatimilehin-Daniel force-pushed the fix/deduplicate-contributor-fetching branch from 68c23b8 to 781280e Compare August 1, 2026 18:38
@sshdopey

sshdopey commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@sshdopey

sshdopey commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@sshdopey

sshdopey commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

.or(page.locator('body')) always resolves to 2 elements when both
body and h1 are present, causing Playwright strict mode to reject it.

Replaced with:
- .first() on the h1 locator (heading is always present)
- .count() guard before asserting the withdraw button, falling back
  to body.toBeVisible() when no withdraw button is rendered
@sshdopey

sshdopey commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

Same fix as feat/consolidate-localstorage-stores — the CI 4-file run
measures 49.69% branch coverage, just under the 50% threshold causing
Jest to exit 1 even though all tests pass.
@sshdopey

sshdopey commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Performance] useTopContributors and useContributorLeaderboard-style hooks duplicate fetching for the same campaign

4 participants